﻿/**	@file		std_auto_ptr.hpp
 *	@date		(2007-08-14 23:40:18)/(2014-11-16 13:59:43)
 *-----------------------------------------------------------------------------
 *	@version	1.0.6.6
 *	@author		Nick Shallery	(nicknide@gmail.com)
 *	@copyright	YOU HAVE ALL LEFT WITH THIS CODE WHILE YOU KEEP COMMENT IN EVERY COPY.
 *-----------------------------------------------------------------------------
**/

#if			!defined(__LOLIX__TOY__STD_AUTO_PTR__NICK__K_IN_G__)
#define		__LOLIX__TOY__STD_AUTO_PTR__NICK__K_IN_G__
//==============================================================================
//--------------------------------------------------------------------------
#if			defined(__cplusplus)

#if			!defined(__LOLIX__TOY_ALLOCATOR__K_IN_G__)
	#include	"./allocator.h"
#endif	//	__LOLIX__TOY_ALLOCATOR__K_IN_G__

#if			!defined(__LOLIX__TOY__L_X_ASSERT_NICK__K_IN_G__)
	#include	"./lx_assert.h"
#endif	//	__LOLIX__TOY__L_X_ASSERT_NICK__K_IN_G__

#if			!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)
	#include	"./std_v2t.hpp"
#endif	//	!defined(__LOLIX__TOY__STD_V2T__NICK__K_IN_G__)


namespace lolix{namespace toy{

template<typename _Ty, typename _Alc = allocator<void> >
class	auto_ptr
	: private	v2t_trait<_Ty>
{
	typedef	auto_ptr<_Ty, _Alc>	this_type;
	typedef	v2t_trait<_Ty>		base_type;

	//struct	_modi_pptr
	//	{
	//	_Ty* _ptr;
	//	auto_ptr<_Ty, _Alc>& _ct;
	//	LOLIX_INLINE_CALL	_modi_pptr(auto_ptr<_Ty, _Alc>& ct)
	//		: _ct(ct)
	//		, _ptr(ct._ptr)
	//		{
	//		}

	//	LOLIX_INLINE_CALL	~_modi_pptr(void)
	//		{
	//		_ct.reset(_ptr);
	//		//if ( _ptr )
	//		//	_ptr->release();
	//		}

	//	LOLIX_INLINE_CALL	operator _Ty** (void)
	//		{
	//		return &_ptr;
	//		}
	//	};

	struct	_param_type
	{
		LOLIX_INLINE_CALL	_param_type(_Ty* ptr, size_type sz, _Alc alc)
			: allocator(alc), pointer(ptr), size(sz){}
		_Alc		allocator;
		_Ty*		pointer;
		size_type	size;
	};
public:
	typedef	typename base_type::const_pointer			const_pointer;
	typedef	typename base_type::const_reference			const_reference;
	typedef	typename base_type::pointer					pointer;
	typedef	typename base_type::reference				reference;
	typedef	typename base_type::size_type				size_type;
	typedef	typename base_type::value_type		element_type;
	typedef	typename _Alc::template rebind<_Ty>::other	allocator_type;
	typedef	_param_type							construct_type;

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>(void)	:_ptr(0), _size(0), _alc(){}
	template<typename _To, typename _Ao>
	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( auto_ptr<_To, _Ao>& o )
		: _ptr(o._ptr), _size(o._size), _alc(o._alc)
		{
			o._ptr = 0;
			o._size = 0;
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( auto_ptr<_Ty, _Alc>& o )
		: _ptr(o._ptr), _size(o._ptr), _alc(o._alc)
		{
			o._ptr = 0;
			o._size = 0;
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( _Ty* ptr )
		: _ptr(ptr), _size(1), _alc()
		{
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( _Ty* ptr, _Alc alc )
		: _ptr(ptr), _size(1), _alc(alc)
		{
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( _Ty* ptr, size_type size, _Alc alc )
		: _ptr(ptr), _size(size), _alc(alc)
		{
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>( _Ty* ptr, size_type size)
		: _ptr(ptr), _size(size), _alc()
		{
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>(_Alc alc)
		: _ptr(0), _size(0), _alc(alc)
		{
		}

	LOLIX_INLINE_CALL	auto_ptr<_Ty, _Alc>(const _param_type& ct)
		: _ptr(ct.pointer), _size(ct.size), _alc(ct.allocator)
		{
		}

	LOLIX_INLINE_CALL	~auto_ptr<_Ty, _Alc>(void)
		{
			LOLIX_DESTROY(_ptr, _size);
			_alc.deallocate(_ptr, _size);
		}

	template<typename _To, typename _Ao>
	LOLIX_INLINE_CALL	this_type&		operator=(auto_ptr<_To, _Ao>& o)
		{
		this_type tmp(o);
		tmp.swap(*this);
		return *this;
		}

	LOLIX_INLINE_CALL	pointer			operator->(void)
		{
		return _ptr;
		}
	LOLIX_INLINE_CALL	const_pointer	operator->(void)const
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	reference		operator*(void)
		{
		return *_ptr;
		}

	LOLIX_INLINE_CALL	const_reference	operator*(void)const
		{
		return *_ptr;
		}

	LOLIX_INLINE_CALL	reference		operator[](size_type pos)
		{
		LOLIX_ASSERT(pos < _size, "out_of_range, during auto_ptr::operator[](size_type) invoke");
		return _ptr[pos];
		}
	LOLIX_INLINE_CALL	const_reference	operator[](size_type pos)const
		{
		LOLIX_ASSERT(pos < _size, "out_of_range, during auto_ptr::operator[](size_type) invoke");
		return _ptr[pos];
		}

	LOLIX_INLINE_CALL	pointer			get(void)
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	const_pointer	get(void)const
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	void	reset(void)
		{
		this_type	tmp(_alc);
		tmp.swap(*this);
		}

	LOLIX_INLINE_CALL	void	reset(_Ty* ptr)
		{
		this_type tmp(ptr, _alc);
		tmp.swap(*this);
		}
	LOLIX_INLINE_CALL	void	reset(_Ty* ptr, size_type size)
		{
		this_type tmp(ptr, size, _alc);
		tmp.swap(*this);
		}

	LOLIX_INLINE_CALL	void	reset(_Ty* ptr, _Alc alc)
		{
		this_type	tmp(ptr, alc);
		tmp.swap(*this);
		}

	LOLIX_INLINE_CALL	void	reset(_Ty* ptr, size_type size, _Alc alc)
		{
		this_type	tmp(ptr, size, alc);
		tmp.swap(*this);
		}

	LOLIX_INLINE_CALL	operator _Ty*(void)
		{
		return _ptr;
		}

	LOLIX_INLINE_CALL	operator _Ty* const(void)const
		{
		return _ptr;
		}

	//LOLIX_INLINE_CALL	_modi_pptr operator& (void)
	//	{
	//	return _modi_pptr(*this);
	//	}

	LOLIX_INLINE_CALL	_Ty*	release(void)
		{
		_Ty* tmp = _ptr;
		_ptr = 0;	_size = 0;
		return tmp;
		}

	LOLIX_INLINE_CALL	void	swap(this_type& o)
		{
		lolix::swap(o._ptr, _ptr);
		lolix::swap(o._size, _size);
		lolix::swap(o._alc, _alc);
		}

	LOLIX_INLINE_CALL	_Alc	get_allocator(void)const
		{
		return _alc;
		}

#undef		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC
#define		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(__lx_v__)		\
			LOLIX_INLINE_CALL	bool operator __lx_v__ (const this_type& o)const{return _ptr __lx_v__ o._ptr;}
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(==);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(!=);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(<);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(<=);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(>);
			__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC(>=);
#undef		__LOLIX__TMP__DEFINE__LOGIC_CMP_FUNC

private:
	_Ty*				_ptr;
	lolix::size_type	_size;
	allocator_type		_alc;
};


}}

namespace lolix{
	template<typename _Ty, typename _Talc>
	LOLIX_INLINE_CALL void swap(toy::auto_ptr<_Ty, _Talc>& tl, toy::auto_ptr<_Ty, _Talc>& tr)
	{ return tl.swap(tr); }
}


//#define		LOLI_PTR(loli_ptr_name, ptr_val)	::lolix::toy::auto_ptr<REBIND_TYPE(ptr_val)>	loli_ptr_name(ptr_val)


#endif	//	defined(__cplusplus)


//--------------------------------------------------------------------------
//==============================================================================
#endif	//	!defined(__LOLIX__TOY__STD_AUTO_PTR__NICK__K_IN_G__)

